package com.yf.exam.modules.paper.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yf.ability.redis.service.RedisService;
import com.yf.ability.upload.service.UploadService;
import com.yf.base.api.exception.ServiceException;
import com.yf.exam.enums.PaperExState;
import com.yf.exam.modules.exam.dto.request.ExamFaceCheckReqDTO;
import com.yf.exam.modules.exam.entity.Exam;
import com.yf.exam.modules.exam.service.ExamService;
import com.yf.exam.modules.paper.dto.request.PaperCaptureReqDTO;
import com.yf.exam.modules.paper.dto.response.CaptureRespDTO;
import com.yf.exam.modules.paper.entity.Paper;
import com.yf.exam.modules.paper.entity.PaperCapture;
import com.yf.exam.modules.paper.mapper.PaperCaptureMapper;
import com.yf.exam.modules.paper.service.PaperCaptureService;
import com.yf.exam.modules.paper.service.PaperService;
import com.yf.system.modules.user.UserUtils;
import com.yf.system.modules.user.dto.response.FaceCheckRespDTO;
import com.yf.system.modules.user.service.SysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.MessageFormat;
import java.util.Calendar;
import java.util.Date;

/**
* <p>
* 试卷考题业务实现类
* </p>
*
* @author 聪明笨狗
* @since 2020-09-19 22:30
*/
@Service
public class PaperCaptureServiceImpl extends ServiceImpl<PaperCaptureMapper, PaperCapture> implements PaperCaptureService {

    @Autowired
    private PaperService paperService;

    @Autowired
    private ExamService examService;

    @Autowired
    private RedisService redisService;

    @Autowired
    private UploadService uploadService;

    @Autowired
    private SysUserService sysUserService;


    @Override
    public CaptureRespDTO save(PaperCaptureReqDTO reqDTO) {

        Paper paper = paperService.getById(reqDTO.getPaperId());
        String userId = paper.getUserId();

        PaperCapture capture = new PaperCapture();
        capture.setPaperId(reqDTO.getPaperId());
        capture.setUserId(userId);
        capture.setExamId(paper.getExamId());

        Exam exam = examService.getById(paper.getExamId());
        // 响应类
        CaptureRespDTO respDTO = new CaptureRespDTO();
        // 无限制响应
        respDTO.setFaceChance(0);
        respDTO.setIsBreak(false);
        respDTO.setFailCount(0);

        // 无需人脸识别
        if(exam.getFaceCheck()==null
                || !exam.getFaceCheck()
                || exam.getFaceChance() == null
                || exam.getFaceChance() == 0){
            // base64转URL
            String faceImage = uploadService.uploadBase64(reqDTO.getBase64(), IdWorker.getIdStr() + ".jpg");
            capture.setCapture(faceImage);
            // 保存截屏
            this.save(capture);
            return respDTO;
        }

        // 总机会数
        respDTO.setFaceChance(exam.getFaceChance());
        respDTO.setIsBreak(false);

        // 进行人脸识别
        FaceCheckRespDTO faceDTO = sysUserService.faceCheck(reqDTO.getBase64(), false);
        // 成功失败都保存
        capture.setCapture(faceDTO.getFaceImage());

        // 识别通过删除错误记录
        String key = MessageFormat.format("yf:exam-face-check:{0}-{1}", userId, paper.getId());
        if(faceDTO.isPass()){
            redisService.del(key);
            respDTO.setFailCount(0);
        }else{
            JSONObject json = redisService.getJson(key);
            int count = 1;
            if(json == null){
                json = new JSONObject();
            }else {
                count = json.getInteger("count");
                count += 1;
            }

            if(count >= exam.getFaceChance()){
                respDTO.setIsBreak(true);
                paperService.handExam(paper.getId(), PaperExState.FACE_FAIL, MessageFormat.format("连续{0}次人脸识别失败，系统强制交卷！", String.valueOf(count)));
            }

            // 有效期为考试截止时间
            Calendar cl = Calendar.getInstance();
            cl.setTime(paper.getLimitTime());
            long now = System.currentTimeMillis();
            long end = paper.getLimitTime().getTime();
            long sec = (end - now) / 1000;

            // 设置值
            json.put("count", count);
            redisService.set(key, json.toJSONString(), sec);
            // 返回响应
            respDTO.setFailCount(count);
        }

        // 先保存截屏
        this.save(capture);
        return respDTO;
    }


    @Override
    public FaceCheckRespDTO faceCheck(ExamFaceCheckReqDTO reqDTO) {

        // 进行人脸识别
        FaceCheckRespDTO respDTO = sysUserService.faceCheck(reqDTO.getBase64(), false);

        // 存档
        PaperCapture capture = new PaperCapture();
        capture.setSuccess(respDTO.isPass());

        if(respDTO.isPass()){
            // 5分钟有效
            Calendar cl = Calendar.getInstance();
            cl.setTimeInMillis(System.currentTimeMillis());
            cl.add(Calendar.MINUTE, 5);
            capture.setExpireTime(cl.getTime());
        }

        capture.setCapture(respDTO.getFaceImage());
        capture.setExamId(reqDTO.getExamId());
        // 当前用户
        capture.setUserId(UserUtils.getUserId());
        capture.setCreateTime(new Date());
        this.save(capture);

        return respDTO;
    }

    @Override
    public void checkFace(String examId, String userId) {
        QueryWrapper<PaperCapture> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .eq(PaperCapture::getExamId, examId)
                .eq(PaperCapture::getUserId, userId)
                .eq(PaperCapture::getSuccess, true)
                .ge(PaperCapture::getExpireTime, new Date());

        int count = this.count(wrapper);
        if(count == 0){
            throw new ServiceException("人脸认证信息校验失败！");
        }
    }
}
